using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Linq;
using System.Xml.Linq;
using System.IO;
using XLETL.Common;
using XLETL.Model;

namespace XLETL.BLL
{
    	/// <summary>
	/// A business component to manage database objects
	/// </summary>
    public class DB
    {
        private readonly string StorageDB;

        public DB()
        {
        }
      
      public DB(string storageBase)
        {
          if (string.IsNullOrEmpty(storageBase))
          {
            throw new ArgumentNullException("storageBase");
          }

          StorageDB = storageBase + GlobalCache.DB_STORAGE_PATH;
      }
        /// <summary>
        /// Get Database List as a Generic List of DBInfo that inclulde database
        /// details, and their relations with list of users, and list of tasks.
        /// </summary>
        public List<DBInfo> GetDeepDBList()
        {
            Task task = new Task();
            User user = new User();

            if (File.Exists(GlobalCache.DB_STORAGE_PATH))
            {
                XElement existingDBs = XElement.Load(GlobalCache.DB_STORAGE_PATH);

                var dbs = from dbElement in existingDBs.Elements(DBInfo.DB_INFO) orderby DBInfo.DB_FRIENDLY_NAME
                                select new DBInfo
                                {
                                    DBId = (Guid)dbElement.Element(DBInfo.DB_ID),
                                    DBFriendlyName = (string)dbElement.Element(DBInfo.DB_FRIENDLY_NAME),
                                    DBDesc = (string)dbElement.Element(DBInfo.DB_DESC),
                                    ConnString = (string)dbElement.Element(DBInfo.CONN_STRING),
                                    DatabaseName = (string)dbElement.Element(DBInfo.DATABASE_NAME),
                                    DALClassName = (string)dbElement.Element(DBInfo.DAL_CLASSNAME),
                                    UserInfoList = user.GetUsers((Guid)dbElement.Element(DBInfo.DB_ID)),
                                    TaskInfoList =  task.GetTasks((Guid)dbElement.Element(DBInfo.DB_ID))
                                };
                return dbs.ToList<DBInfo>();
            }
            else return new List<DBInfo>();            
        }

		/// <summary>
		/// Remove the database from the system.
		/// </summary>
		/// <param name="companyId">Unique identifier for a Database</param>
		public bool DeleteDB(int dbId){

			return false;
		}

		/// <summary>
		/// Search for a database given it's unique identifier
		/// </summary>
		/// <param name="companyId">Unique identifier for a database</param>
		public DBInfo GetDBDetails(Guid dbId){

            if (File.Exists(GlobalCache.DB_STORAGE_PATH))
            {
                XElement existingDBs = XElement.Load(GlobalCache.DB_STORAGE_PATH);

                var dbs = from dbElement in existingDBs.Elements(DBInfo.DB_INFO)
                          let did = (Guid)dbElement.Element(DBInfo.DB_ID)
                          where did.Equals(dbId)
                          select new DBInfo
                          {
                              DBId = (Guid)dbElement.Element(DBInfo.DB_ID),
                              DBFriendlyName = (string)dbElement.Element(DBInfo.DB_FRIENDLY_NAME),
                              DBDesc = (string)dbElement.Element(DBInfo.DB_DESC),
                              ConnString = (string)dbElement.Element(DBInfo.CONN_STRING),
                              DatabaseName = (string)dbElement.Element(DBInfo.DATABASE_NAME),
                              DALClassName = (string)dbElement.Element(DBInfo.DAL_CLASSNAME)
                          };

                List<DBInfo> ls = dbs.ToList<DBInfo>();
                if (ls.Count > 0)
                {
                    return ls[0];
                }
                else { return null; }
                
            }
            else return null;
		}		

        /// <summary>
        /// Save Database object into the system.
        /// </summary>
        /// <param name="company">A database business entity</param>
        public bool SaveDB(DBInfo db)
        {
            if (db == null)
            {
                throw new ArgumentNullException("Parameter \"db\" is null");
            }

            XElement dbs = new XElement(DBInfo.DB_COL);

            if (File.Exists(GlobalCache.DB_STORAGE_PATH))
            {
                // load all databases
                XElement existingDBs = XElement.Load(GlobalCache.DB_STORAGE_PATH);
                IEnumerable<XElement> singleDB = null;
                Guid dbID;
                
                // only update 
                if (!db.DBId.Equals(Guid.Empty))
                {
                    
                    dbID = db.DBId;

                    //obtain a single database
                    singleDB = (from targetDB in existingDBs.Elements(DBInfo.DB_INFO)
                                                           where ((Guid)targetDB.Element(DBInfo.DB_ID)).Equals(dbID)
                                                           select targetDB);                    
                }
                else
                {
                    dbID = Guid.NewGuid();
                }

                XElement newDB = new XElement(DBInfo.DB_INFO,
                new XElement(DBInfo.DB_ID, dbID),
                new XElement(DBInfo.DB_FRIENDLY_NAME, db.DBFriendlyName),
                new XElement(DBInfo.DB_DESC, db.DBDesc),
                new XElement(DBInfo.CONN_STRING, db.ConnString),
                new XElement(DBInfo.DATABASE_NAME, db.DatabaseName),
                new XElement(DBInfo.DAL_CLASSNAME, db.DALClassName)
                );

                if (singleDB != null)
                {
                    //update database, should only be 1
                    foreach (XElement xe in singleDB)
                    {
                        //xe.Remove();
                        xe.ReplaceWith(newDB);
                    }

                    existingDBs.Save(GlobalCache.DB_STORAGE_PATH);

                }
                else
                {
                    dbs.Add(existingDBs.Elements(DBInfo.DB_INFO));

                    dbs.Add(newDB);
                    dbs.Save(GlobalCache.DB_STORAGE_PATH);
                }

                return true;
            }
            else
            {
                return false;
            }
           
            
        }

        ///<summary>
        /// Get Database List as a Generic List of DBInfo that inclulde database
        /// details, and their relations with list of users, and list of tasks.
        /// </summary>
        public List<DBInfo> GetDBs()
        {
            if (File.Exists(GlobalCache.DB_STORAGE_PATH))
            {
                XElement existingDBs = XElement.Load(GlobalCache.DB_STORAGE_PATH);

                var dbs = from dbElement in existingDBs.Elements(DBInfo.DB_INFO)
                                select new DBInfo
                                {
                                    DBId = (Guid)dbElement.Element(DBInfo.DB_ID),
                                    DBFriendlyName = (string)dbElement.Element(DBInfo.DB_FRIENDLY_NAME),
                                    DBDesc = (string)dbElement.Element(DBInfo.DB_DESC),
                                    ConnString = (string)dbElement.Element(DBInfo.CONN_STRING),
                                    DatabaseName = (string)dbElement.Element(DBInfo.DATABASE_NAME),
                                    DALClassName = (string)dbElement.Element(DBInfo.DAL_CLASSNAME)
                                };
                return dbs.ToList<DBInfo>();
            }
            else return new List<DBInfo>();            
        }
}
}
